/**
 * 请求控制工具函数
 */

/**
 * 请求去重管理器
 */
class RequestDeduplicator {
  constructor() {
    this.pendingRequests = new Map();
  }

  /**
   * 执行去重请求
   * @param {string} key - 请求唯一标识
   * @param {Function} requestFn - 请求函数
   * @returns {Promise} 请求结果
   */
  async request(key, requestFn) {
    // 如果相同请求正在进行中，返回现有的Promise
    if (this.pendingRequests.has(key)) {
      return this.pendingRequests.get(key);
    }

    // 创建新的请求Promise
    const requestPromise = this._executeRequest(requestFn);

    // 存储请求Promise
    this.pendingRequests.set(key, requestPromise);

    try {
      const result = await requestPromise;
      return result;
    } finally {
      // 请求完成后移除
      this.pendingRequests.delete(key);
    }
  }

  /**
   * 执行请求
   * @param {Function} requestFn - 请求函数
   * @returns {Promise} 请求结果
   */
  async _executeRequest(requestFn) {
    if (typeof requestFn !== 'function') {
      throw new Error('请求函数必须是函数');
    }
    return await requestFn();
  }

  /**
   * 取消指定请求
   * @param {string} key - 请求唯一标识
   */
  cancel(key) {
    if (this.pendingRequests.has(key)) {
      this.pendingRequests.delete(key);
    }
  }

  /**
   * 取消所有请求
   */
  cancelAll() {
    this.pendingRequests.clear();
  }

  /**
   * 获取当前进行中的请求数量
   * @returns {number} 请求数量
   */
  getPendingCount() {
    return this.pendingRequests.size;
  }
}

/**
 * LRU缓存管理器
 */
class LRUCache {
  constructor(maxSize = 100) {
    this.maxSize = maxSize;
    this.cache = new Map();
  }

  /**
   * 获取缓存值
   * @param {string} key - 缓存键
   * @returns {any} 缓存值
   */
  get(key) {
    if (this.cache.has(key)) {
      // 重新设置以更新访问顺序
      const value = this.cache.get(key);
      this.cache.delete(key);
      this.cache.set(key, value);
      return value;
    }
    return undefined;
  }

  /**
   * 设置缓存值
   * @param {string} key - 缓存键
   * @param {any} value - 缓存值
   */
  set(key, value) {
    if (this.cache.has(key)) {
      // 更新现有值
      this.cache.delete(key);
    } else if (this.cache.size >= this.maxSize) {
      // 删除最久未使用的项
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    this.cache.set(key, value);
  }

  /**
   * 删除缓存值
   * @param {string} key - 缓存键
   * @returns {boolean} 是否删除成功
   */
  delete(key) {
    return this.cache.delete(key);
  }

  /**
   * 清空缓存
   */
  clear() {
    this.cache.clear();
  }

  /**
   * 检查是否存在缓存
   * @param {string} key - 缓存键
   * @returns {boolean} 是否存在
   */
  has(key) {
    return this.cache.has(key);
  }

  /**
   * 获取缓存大小
   * @returns {number} 缓存大小
   */
  size() {
    return this.cache.size;
  }

  /**
   * 获取所有键
   * @returns {Array} 所有键
   */
  keys() {
    return Array.from(this.cache.keys());
  }

  /**
   * 获取所有值
   * @returns {Array} 所有值
   */
  values() {
    return Array.from(this.cache.values());
  }
}

/**
 * 并发请求控制器
 */
class ConcurrencyController {
  constructor(maxConcurrency = 5) {
    this.maxConcurrency = maxConcurrency;
    this.running = 0;
    this.queue = [];
  }

  /**
   * 执行请求
   * @param {Function} requestFn - 请求函数
   * @param {Object} options - 选项
   * @returns {Promise} 请求结果
   */
  async execute(requestFn, options = {}) {
    const {
      priority = 0, // 优先级，数字越大优先级越高
      timeout = 0, // 超时时间（毫秒）
      retry = 0, // 重试次数
      retryDelay = 1000, // 重试延迟（毫秒）
    } = options;

    return new Promise((resolve, reject) => {
      const request = {
        requestFn,
        priority,
        timeout,
        retry,
        retryDelay,
        resolve,
        reject,
        attempts: 0,
      };

      // 按优先级插入队列
      this._insertByPriority(request);
      this._processQueue();
    });
  }

  /**
   * 按优先级插入请求
   * @param {Object} request - 请求对象
   */
  _insertByPriority(request) {
    let inserted = false;
    for (let i = 0; i < this.queue.length; i++) {
      if (request.priority > this.queue[i].priority) {
        this.queue.splice(i, 0, request);
        inserted = true;
        break;
      }
    }
    if (!inserted) {
      this.queue.push(request);
    }
  }

  /**
   * 处理队列
   */
  async _processQueue() {
    if (this.running >= this.maxConcurrency || this.queue.length === 0) {
      return;
    }

    const request = this.queue.shift();
    this.running++;

    try {
      const result = await this._executeWithTimeout(request);
      request.resolve(result);
    } catch (error) {
      if (request.attempts < request.retry) {
        // 重试
        request.attempts++;
        setTimeout(() => {
          this.queue.unshift(request);
          this._processQueue();
        }, request.retryDelay);
      } else {
        request.reject(error);
      }
    } finally {
      this.running--;
      this._processQueue();
    }
  }

  /**
   * 执行带超时的请求
   * @param {Object} request - 请求对象
   * @returns {Promise} 请求结果
   */
  async _executeWithTimeout(request) {
    if (request.timeout <= 0) {
      return await request.requestFn();
    }

    return Promise.race([
      request.requestFn(),
      new Promise((_, reject) => {
        setTimeout(() => reject(new Error('请求超时')), request.timeout);
      }),
    ]);
  }

  /**
   * 获取队列状态
   * @returns {Object} 队列状态
   */
  getStatus() {
    return {
      running: this.running,
      queued: this.queue.length,
      maxConcurrency: this.maxConcurrency,
    };
  }

  /**
   * 清空队列
   */
  clearQueue() {
    this.queue.forEach(request => {
      request.reject(new Error('队列已清空'));
    });
    this.queue = [];
  }
}

// 创建全局实例
const requestDeduplicator = new RequestDeduplicator();
const lruCache = new LRUCache(100);
const concurrencyController = new ConcurrencyController(5);

/**
 * 防重复请求
 * @param {string} key - 请求唯一标识
 * @param {Function} requestFn - 请求函数
 * @returns {Promise} 请求结果
 */
export function deduplicateRequest(key, requestFn) {
  return requestDeduplicator.request(key, requestFn);
}

/**
 * 带缓存的请求
 * @param {string} key - 缓存键
 * @param {Function} requestFn - 请求函数
 * @param {Object} options - 选项
 * @returns {Promise} 请求结果
 */
export async function cachedRequest(key, requestFn, options = {}) {
  const { cache = lruCache, ttl = 0 } = options;

  // 检查缓存
  if (cache.has(key)) {
    const cached = cache.get(key);
    if (ttl <= 0 || Date.now() - cached.timestamp < ttl) {
      return cached.data;
    }
    cache.delete(key);
  }

  // 执行请求
  const data = await requestFn();

  // 缓存结果
  cache.set(key, {
    data,
    timestamp: Date.now(),
  });

  return data;
}

/**
 * 并发控制请求
 * @param {Function} requestFn - 请求函数
 * @param {Object} options - 选项
 * @returns {Promise} 请求结果
 */
export function controlledRequest(requestFn, options = {}) {
  return concurrencyController.execute(requestFn, options);
}

/**
 * 创建请求去重器
 * @returns {RequestDeduplicator} 去重器实例
 */
export function createRequestDeduplicator() {
  return new RequestDeduplicator();
}

/**
 * 创建LRU缓存
 * @param {number} maxSize - 最大缓存大小
 * @returns {LRUCache} 缓存实例
 */
export function createLRUCache(maxSize = 100) {
  return new LRUCache(maxSize);
}

/**
 * 创建并发控制器
 * @param {number} maxConcurrency - 最大并发数
 * @returns {ConcurrencyController} 控制器实例
 */
export function createConcurrencyController(maxConcurrency = 5) {
  return new ConcurrencyController(maxConcurrency);
}

/**
 * 请求重试装饰器
 * @param {Function} requestFn - 请求函数
 * @param {Object} options - 选项
 * @returns {Function} 装饰后的函数
 */
export function withRetry(requestFn, options = {}) {
  const {
    retries = 3,
    delay = 1000,
    backoff = 2,
    retryCondition = error => true,
  } = options;

  return async function (...args) {
    let lastError;

    for (let i = 0; i <= retries; i++) {
      try {
        return await requestFn.apply(this, args);
      } catch (error) {
        lastError = error;

        if (i === retries || !retryCondition(error)) {
          throw error;
        }

        const delayTime = delay * Math.pow(backoff, i);
        await new Promise(resolve => setTimeout(resolve, delayTime));
      }
    }

    throw lastError;
  };
}

/**
 * 请求超时装饰器
 * @param {Function} requestFn - 请求函数
 * @param {number} timeout - 超时时间（毫秒）
 * @returns {Function} 装饰后的函数
 */
export function withTimeout(requestFn, timeout) {
  return async function (...args) {
    return Promise.race([
      requestFn.apply(this, args),
      new Promise((_, reject) => {
        setTimeout(() => reject(new Error('请求超时')), timeout);
      }),
    ]);
  };
}

/**
 * 请求缓存装饰器
 * @param {Function} requestFn - 请求函数
 * @param {Object} options - 选项
 * @returns {Function} 装饰后的函数
 */
export function withCache(requestFn, options = {}) {
  const {
    cache = lruCache,
    keyGenerator = (...args) => JSON.stringify(args),
    ttl = 0,
  } = options;

  return async function (...args) {
    const key = keyGenerator(...args);

    // 检查缓存
    if (cache.has(key)) {
      const cached = cache.get(key);
      if (ttl <= 0 || Date.now() - cached.timestamp < ttl) {
        return cached.data;
      }
      cache.delete(key);
    }

    // 执行请求
    const data = await requestFn.apply(this, args);

    // 缓存结果
    cache.set(key, {
      data,
      timestamp: Date.now(),
    });

    return data;
  };
}

/**
 * 批量请求
 * @param {Array} requests - 请求数组
 * @param {Object} options - 选项
 * @returns {Promise} 请求结果数组
 */
export async function batchRequest(requests, options = {}) {
  const { concurrency = 5, failFast = false } = options;

  const controller = new ConcurrencyController(concurrency);
  const results = [];
  const errors = [];

  const promises = requests.map(async (request, index) => {
    try {
      const result = await controller.execute(request);
      results[index] = { success: true, data: result };
      return result;
    } catch (error) {
      results[index] = { success: false, error };
      errors.push(error);

      if (failFast) {
        throw error;
      }
    }
  });

  try {
    await Promise.all(promises);
  } catch (error) {
    if (failFast) {
      throw error;
    }
  }

  return {
    results,
    errors,
    successCount: results.filter(r => r.success).length,
    errorCount: errors.length,
  };
}

/**
 * 请求队列
 * @param {Array} requests - 请求数组
 * @param {Object} options - 选项
 * @returns {Promise} 请求结果数组
 */
export async function queueRequest(requests, options = {}) {
  const { concurrency = 1, delay = 0 } = options;

  const controller = new ConcurrencyController(concurrency);
  const results = [];

  for (let i = 0; i < requests.length; i++) {
    try {
      const result = await controller.execute(requests[i]);
      results.push({ success: true, data: result });
    } catch (error) {
      results.push({ success: false, error });
    }

    // 延迟
    if (delay > 0 && i < requests.length - 1) {
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  return results;
}

// 导出类和实例
export {
  RequestDeduplicator,
  LRUCache,
  ConcurrencyController,
  requestDeduplicator,
  lruCache,
  concurrencyController,
};
